package com.hmdp.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

/**
 * 全局id生成器工具,id生成规则为:
 * 一位符号位+31时间戳32位+序列号32位
 * 0+1640995200的二进制(=1100001011010110000000000000000)+32位序列号
 */
@Component
@Slf4j
public class RedisIdGenerate {
    /**
     * 开始时间戳，用于计算id
     */
    public static final long START_TIMESTAMP = 1640995200L;//表示2022-01-01 00:00:00
    /**
     * 序列号位数
     */
    public static final int SEQUENCE_BIT = 32;

    private StringRedisTemplate stringRedisTemplate;

    public RedisIdGenerate(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    /**
     * 生成全局唯一id,确保在每一个业务场景下生成的id是唯一的
     *
     * @return
     */
    public long generateId(String keyPrefix) {
        //1.生成时间戳
        long end = LocalDateTime.now().toEpochSecond(ZoneOffset.UTC);
        long timestamp = end - START_TIMESTAMP;

        //2.生成序列号
        String date = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy:MM:dd"));
        // 2.2.自增长
        long count = stringRedisTemplate.opsForValue().increment("icr:" + keyPrefix + ":" + date);//返回值为自增后的值
        //自增操作该key的值，如果key不存在，则初始化为0，然后自增1,否则自增1，并返回自增后的值

        //3.拼接并返回id
        log.info("生成的id为:{}", timestamp << SEQUENCE_BIT | count);
        return timestamp << SEQUENCE_BIT | count;//<<指的是位移运算符，左移32位，即序列号位数,|指的是按位或运算符，将时间戳和序列号按位或合并成一个64位的整数
        /**
         * 按位或运算符的规则：
         * 也就是timestamp向左移动32位，然后与count按位或，结果就是64位的整数，其中前32位是timestamp，后32位是count
         * timestamp向左移动32位,前面32为全0，全0和任何数按位或结果都是该数
         * 0|0=0
         * 1|0=1
         * 0|1=1
         * 1|1=1
         */

    }

}
